// Copyright 2007 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.enterprise.onebox.apps;

import java.util.*;

/**
 * Groups result headers with a list of results as well as provides a way to
 * serialize the result for transport.
 * 
 * @author amsmith@google.com (Adam Smith)
 */
public class SimpleOneBoxResults {
  private String providerName;
  private String query;
  private String link;
  private int totalResults;
  private List<ModuleResult> results;
 
  public SimpleOneBoxResults() {
    providerName = "";
    query = "";
    link = "";
    totalResults = 0;
    results = new LinkedList<ModuleResult>();
  }
  
  public void setProviderName(String providerName) {
    this.providerName = providerName;
  }
  public String getProviderName() {
    return providerName;
  }
  
  public void setQuery(String query) {
    this.query = query;
  }
  public String getQuery(String query) {
    return query;
  }
  
  public void setTotalResults(int totalResults) {
    this.totalResults = totalResults;
  }
  public int getTotalResults() {
    return totalResults;
  }
  
  
  public void setResults(List<ModuleResult> results) {
    this.results = results;
  }
  public List<ModuleResult> getResults() {
    return results;
  }
  
  public void setLink(String link) {
    this.link = link;
  }
  
  public String getLink() {
    return link;
  }
  
  /**
   * Returns an XML snippet string version of this results set.
   */
  @Override
  public String toString() {
    String titleText = providerName + " results for " + query + " - " + totalResults;
    
    StringBuffer buffer = new StringBuffer();
    buffer.append("<?xml version='1.0' encoding='UTF-8'?>\n");
    buffer.append("<OneBoxResults>\n");
    buffer.append("  <provider>" + providerName + "</provider>\n");
    buffer.append("  <title>\n");
    buffer.append("    <urlText>" + titleText + "</urlText>\n");
    buffer.append("    <urlLink>" + link + "</urlLink>\n");
    buffer.append("  </title>\n");
    for (ModuleResult r : results) {
      buffer.append("  <MODULE_RESULT>\n");
      buffer.append("    <U>" + xmlEncodeAttrValue(r.getUrl()) + "</U>\n");
      buffer.append("    <Title>" + xmlEncodeAttrValue(r.getTitle()) + "</Title>\n");
      for (String key : r.fieldsKeySet()) {
        buffer.append(
            "    <Field name=\"" + key + "\">" + r.getField(key) + "</Field>\n");
      }
      buffer.append("  </MODULE_RESULT>\n");
    }
    buffer.append("</OneBoxResults>\n");
    return buffer.toString();
  }
  
  // from google-enterprise-connector-manager.googlecode.com

  private static final String XML_LESS_THAN = "&lt;";
  private static final String XML_AMPERSAND = "&amp;";
  private static final String XML_QUOTE = "&quot;";
  private static final String XML_APOSTROPHE = "&apos;";

  private static String xmlEncodeAttrValue(String val) {
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i < val.length(); i++) {
      char c = val.charAt(i);
      /**
       * Only these characters need to be encoded, according to
       * http://www.w3.org/TR/REC-xml/#NT-AttValue. Actually, we could only
       * encode one of the quote characters if we knew that that was the one
       * used to wrap the value, but we'll play it safe and encode both. TODO:
       * what happens to white-space?
       */
      switch (c) {
      case '<':
        buf.append(XML_LESS_THAN);
        break;
      case '&':
        buf.append(XML_AMPERSAND);
        break;
      case '"':
        buf.append(XML_QUOTE);
        break;
      case '\'':
        buf.append(XML_APOSTROPHE);
        break;
      default:
        buf.append(c);
        break;
      }
    }
    return buf.toString();
  }
  
  /**
   * Groups url and title strings with a map for field data in a transparent and
   * fully modifiable container.
   * 
   * @author amsmith@google.com (Adam Smith)
   */
  public static class ModuleResult {
    private String url;
    private String title;
    private Map<String,String> fields;
    
    public ModuleResult() {
      url = "";
      title = "";
      fields = new HashMap<String,String>();
    }

    public void setTitle(String title) {
      this.title = title;
    }
    
    public String getTitle() {
      return title;
    }

    public void setUrl(String url) {
      this.url = url;
    }
    
    public String getUrl() {
      return url;
    }
    
    public Set<String> fieldsKeySet() {
      return fields.keySet();
    }
    
    public void putField(String key, String value) {
      fields.put(key, value);
    }
    
    public String getField(String key) {
      return fields.get(key);
    }
    
    public void removeField(String key) {
      fields.remove(key);
    }
  }
}

